home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #4 / Amiga Plus CD - 2000 - No. 4.iso / Vollversion / CamD / development / examples / drum / arrows.c next >
C/C++ Source or Header  |  2000-05-15  |  13KB  |  408 lines

  1. /* ======================================================================== *
  2.  *  Arrows.c -- a BOOPSI class implementing increment / decrement arrows
  3.  *                             By Talin.
  4.  *              Copyright © 1991 Sylvan Technical Arts
  5.  * ======================================================================== */
  6.  
  7. #include "std_headers.h"
  8. #include <intuition/cghooks.h>
  9. #include <intuition/gadgetclass.h>
  10. #include <intuition/classes.h>
  11. #include <intuition/imageclass.h>
  12. #include <utility/tagitem.h>
  13. #include <utility/hooks.h>
  14. #include <clib/alib_protos.h>
  15. #include <math.h>
  16.  
  17. #include "arrows.h"
  18.  
  19. extern struct Library   *IntuitionBase,
  20.                         *UtilityBase,
  21.                         *GadToolsBase,
  22.                         *GfxBase;
  23.  
  24. #define INCREMENT       GACT_ALTKEYMAP          /* overload this gadget flag    */
  25.  
  26. #define clamp(a,b,c)    min( max( a, b ), c )   /* constrain b between a and c  */
  27.  
  28. struct ArrowButton {
  29.     ULONG               min,                    /* minimum value                */
  30.                         max,                    /* maximum value                */
  31.                         current;                /* current internal value       */
  32.     UWORD               rate,                   /* rate of increment            */
  33.                         rate_increase,          /* % speed increase per tick    */
  34.                         rate_max;               /* maximum speed                */
  35. };
  36.  
  37. void __asm AsymBevel(   register __a0 struct RastPort *rp,
  38.                         register __a1 struct IBox *b,
  39.                         register __d0 LONG ulpen,
  40.                         register __d1 LONG lrpen,
  41.                         register __d2 LONG fillpen,
  42.                         register __d3 WORD side );
  43.  
  44. void SetupGadgetIBox( struct Gadget *gadget, struct IBox *domain, struct IBox *box )
  45. {
  46.     box->Left = gadget->LeftEdge;
  47.     box->Top = gadget->TopEdge;
  48.     box->Width = gadget->Width;
  49.     box->Height = gadget->Height;
  50.  
  51.     if (gadget->Flags & GRELRIGHT)  box->Left += domain->Width;
  52.     if (gadget->Flags & GRELBOTTOM) box->Top += domain->Height;
  53.  
  54.     if (gadget->Flags & GRELWIDTH)  box->Width += domain->Width;
  55.     if (gadget->Flags & GRELHEIGHT) box->Height += domain->Height;
  56. }
  57.  
  58.     /*  GM_RENDER method handler  */
  59.  
  60. static void arrowdraw(Class *cl, struct gpRender *msg,struct Gadget *g)
  61. {
  62.     if (msg->gpr_Redraw == GREDRAW_REDRAW || msg->gpr_Redraw == GREDRAW_UPDATE)
  63.     {   struct IBox         left_box,
  64.                             right_box;
  65.         struct GadgetInfo   *gi = msg->gpr_GInfo;
  66.         struct RastPort     *rp = msg->gpr_RPort;
  67.         UWORD               *pens = gi->gi_DrInfo->dri_Pens;
  68.         BOOL                dec_selected = 0,
  69.                             inc_selected = 0;
  70.         WORD                symbol_diag_w,
  71.                             symbol_diag_h;
  72.         WORD                x_center,
  73.                             y_center;
  74.         WORD                symbol_height,
  75.                             symbol_y1,
  76.                             symbol_y2,
  77.                             symbol_y3,
  78.                             symbol_y4;
  79.         WORD                sx1,
  80.                             sx2;
  81.  
  82.         SetupGadgetIBox( g, &gi->gi_Domain, &right_box);
  83.  
  84.         if (g->Flags & GFLG_SELECTED)
  85.         {   if (g->Activation & INCREMENT) inc_selected = TRUE;
  86.             else dec_selected = TRUE;
  87.         }
  88.  
  89.         left_box = right_box;
  90.         left_box.Width = right_box.Width / 2;
  91.         right_box.Width = right_box.Width - left_box.Width;
  92.         right_box.Left += left_box.Width;
  93.  
  94.         symbol_diag_w = MIN( left_box.Width - 5, 7);
  95.         symbol_diag_w = MIN( symbol_diag_w, left_box.Height / 3 );
  96.         symbol_diag_h = clamp(3, (left_box.Height - 3) / 2, symbol_diag_w );
  97.  
  98.         symbol_height = symbol_diag_h + symbol_diag_h - (right_box.Height & 1);
  99.  
  100.         x_center = (left_box.Width - symbol_diag_w) / 2;
  101.         y_center = (right_box.Height - symbol_height) / 2;
  102.  
  103.             /* Draw 1st arrow button */
  104.  
  105.         symbol_height--;
  106.         symbol_diag_h--;
  107.         symbol_diag_w--;
  108.         symbol_y1 = left_box.Top + y_center;
  109.         symbol_y2 = symbol_y1 + symbol_diag_h;
  110.         symbol_y4 = symbol_y1 + symbol_height - symbol_diag_h;
  111.         symbol_y3 = symbol_y1 + symbol_height;
  112.  
  113.         AsymBevel(  rp, &left_box,
  114.                     pens[ dec_selected ? SHADOWPEN : SHINEPEN ],
  115.                     pens[ dec_selected ? SHINEPEN : SHADOWPEN ],
  116.                     pens[ dec_selected ? FILLPEN : BACKGROUNDPEN ],
  117.                     0 );
  118.  
  119.             /* draw inner part of right-hand box */
  120.  
  121.         SetAPen(rp,pens[ TEXTPEN ]);
  122.  
  123.         sx1 = left_box.Left + 1 + x_center;
  124.         sx2 = sx1 + symbol_diag_w;
  125.  
  126.         Move( rp, sx1, symbol_y2 );
  127.         Draw( rp, sx2, symbol_y1 );
  128.         Move( rp, sx1, symbol_y4 );
  129.         Draw( rp, sx2, symbol_y3 );
  130.  
  131.         Move( rp, sx1 + 1, symbol_y2 );
  132.         Draw( rp, sx2, symbol_y1 + 1 );
  133.         Move( rp, sx1 + 1, symbol_y4 );
  134.         Draw( rp, sx2, symbol_y3 - 1 );
  135.  
  136.         AsymBevel(  rp, &right_box,
  137.                     pens[ inc_selected ? SHADOWPEN : SHINEPEN ],
  138.                     pens[ inc_selected ? SHINEPEN : SHADOWPEN ],
  139.                     pens[ inc_selected ? FILLPEN : BACKGROUNDPEN ],
  140.                     1 );
  141.  
  142.             /* draw inner part of right-hand box */
  143.  
  144.         SetAPen(rp,pens[ TEXTPEN ]);
  145.  
  146.         sx1 = right_box.Left + x_center;
  147.         sx2 = sx1 + symbol_diag_w;
  148.  
  149.         Move( rp, sx2, symbol_y2 );
  150.         Draw( rp, sx1, symbol_y1 );
  151.         Move( rp, sx2, symbol_y4 );
  152.         Draw( rp, sx1, symbol_y3 );
  153.  
  154.         Move( rp, sx2 - 1, symbol_y2 );
  155.         Draw( rp, sx1, symbol_y1 + 1 );
  156.         Move( rp, sx2 - 1, symbol_y4 );
  157.         Draw( rp, sx1, symbol_y3 - 1 );
  158.     }
  159. }
  160.  
  161. static int TestHit(struct gpInput *msg,struct Gadget *g)
  162. {   struct IBox         gbox;
  163.     short               x = msg->gpi_Mouse.X,
  164.                         y = msg->gpi_Mouse.Y;
  165.  
  166.     SetupGadgetIBox(g,&msg->gpi_GInfo->gi_Domain,&gbox);
  167.  
  168.     if (x >= 0 && y >= 0 && x < gbox.Width && y < gbox.Height)
  169.         return (x > gbox.Width / 2) ? ARROWSTATE_INC : ARROWSTATE_DEC;
  170.  
  171.     return 0;
  172. }
  173.  
  174.     /*  GM_HANDLEINPUT method handler  */
  175.  
  176. static long arrowhandle(Class *cl, struct gpInput *msg,struct Gadget *g)
  177. {
  178.     struct RastPort *rp;
  179.     long            result = GMR_MEACTIVE;
  180.     BOOL            render = FALSE,             /* TRUE if we need to re-render */
  181.                     update = FALSE,             /* TRUE if we need to re-calc   */
  182.                     notify = FALSE;             /* TRUE if we need to broadcast */
  183.     WORD            verify = g->Activation & GACT_RELVERIFY ? GMR_VERIFY : 0;
  184.     struct ArrowButton  *ab = (struct ArrowButton *)INST_DATA( cl, g );
  185.     static          timer_delay;
  186.  
  187.         /* Handle input messages */
  188.  
  189.     if (msg->MethodID == GM_GOACTIVE)       /* classify type of hit         */
  190.     {
  191.         if (msg->gpi_IEvent == NULL) return GMR_NOREUSE;
  192.         ab->rate = 100;
  193.  
  194.         g->Flags |= GFLG_SELECTED;
  195.         if (TestHit(msg,g) == ARROWSTATE_INC) g->Activation |= INCREMENT;
  196.         else g->Activation &= ~INCREMENT;
  197.  
  198.         timer_delay = 2;
  199.  
  200.         render = notify = update = TRUE;
  201.     }
  202.  
  203.     if (msg->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
  204.     {
  205.         if (msg->gpi_IEvent->ie_Code == (UBYTE)(IECODE_LBUTTON+IECODE_UP_PREFIX))
  206.         {
  207.             g->Flags &= ~GFLG_SELECTED;
  208.             result = GMR_NOREUSE | verify;
  209.             render = TRUE;
  210.         }
  211.         else if (msg->gpi_IEvent->ie_Code == (UBYTE)IECODE_RBUTTON)
  212.         {
  213.                 /* check for menu button hit */
  214.  
  215.             g->Flags &= ~GFLG_SELECTED;
  216.             result = GMR_REUSE | verify;
  217.             render = TRUE;
  218.         }
  219.         else
  220.         {   WORD        oldflags = g->Flags,
  221.                         hit = TestHit(msg,g),
  222.                         current_state;
  223.  
  224.             current_state = (g->Activation & INCREMENT) ? ARROWSTATE_INC : ARROWSTATE_DEC;
  225.  
  226.             if (current_state == hit) g->Flags |= GFLG_SELECTED;
  227.             else g->Flags &= ~GFLG_SELECTED;
  228.  
  229.             if (g->Flags != oldflags) render = TRUE;
  230.         }
  231.     }
  232.     else if (msg->gpi_IEvent->ie_Class == IECLASS_TIMER)
  233.     {
  234.         if (timer_delay > 0) timer_delay--;
  235.         else
  236.         {
  237.             update = TRUE;
  238.             ab->rate = ab->rate * ab->rate_increase / 100;
  239.             if (ab->rate > ab->rate_max) ab->rate = ab->rate_max;
  240.         }
  241.     }
  242.  
  243.         /* increment or decrement internal value */
  244.  
  245.     if (update)
  246.     {   LONG            rate = ab->rate / 100;
  247.         LONG            newval;
  248.  
  249.         if (rate < 1) rate = 1;
  250.         if (!(g->Activation & INCREMENT)) rate = -rate;
  251.         newval = clamp(ab->min,ab->current + rate,ab->max);
  252.         if (newval != ab->current)
  253.         {   ab->current = newval;
  254.             notify = TRUE;
  255.         }
  256.     }
  257.  
  258.         /* re-render the gadget */
  259.  
  260.     if (render && (rp = ObtainGIRPort(msg->gpi_GInfo)))
  261.     {
  262.         DoMethod((Object *)g,GM_RENDER,msg->gpi_GInfo,rp,GREDRAW_UPDATE);
  263.         ReleaseGIRPort(rp);
  264.     }
  265.  
  266.         /* notify others that we changed */
  267.  
  268.     if (notify)
  269.     {   struct TagItem  output_tags[ 4 ],
  270.                         *tagout = output_tags;
  271.         WORD            flags = OPUF_INTERIM;
  272.  
  273.             /* build a conditional tag list */
  274.  
  275.         tagout->ti_Tag  = GA_ID;
  276.         tagout->ti_Data = g->GadgetID;
  277.         tagout++;
  278.  
  279.         tagout->ti_Tag  = ARROW_Current;
  280.         tagout->ti_Data = ab->current;
  281.         tagout++;
  282.  
  283.         if (result & GMR_VERIFY)
  284.         {   tagout->ti_Tag  = ARROW_State;
  285.             tagout->ti_Data = 0;
  286.             tagout++;
  287.             flags = 0;
  288.         }
  289.         else if (msg->MethodID == GM_GOACTIVE)
  290.         {   tagout->ti_Tag  = ARROW_State;
  291.             tagout->ti_Data = g->Activation & INCREMENT ? ARROWSTATE_INC : ARROWSTATE_DEC;
  292.             tagout++;
  293.         }
  294.  
  295.         tagout->ti_Tag = TAG_DONE;
  296.  
  297.             /* send notification */
  298.  
  299.         DoMethod( (Object *)g, OM_NOTIFY, output_tags, msg->gpi_GInfo, flags );
  300.     }
  301.  
  302.     return result;
  303. }
  304.  
  305. /* ============================================================================ *
  306.  *  set ArrowButton attributes
  307.  * ============================================================================ */
  308.  
  309. static int setArrowButtonAttrs( Class *cl, Object *o, struct opSet *msg )
  310. {   struct TagItem      *tags = msg->ops_AttrList,
  311.                         *tlist = tags;
  312.     struct ArrowButton  *ab = INST_DATA( cl, o );
  313.     ULONG               tagval;
  314.  
  315.         /* iterate through the tags and setup what values are needed */
  316.  
  317.     while (tags = NextTagItem(&tlist))
  318.     {
  319.         tagval = tags->ti_Data;
  320.         switch (tags->ti_Tag) {
  321.  
  322.         case ARROW_Min:             ab->min = tagval; break;
  323.         case ARROW_Max:             ab->max = tagval; break;
  324.         case ARROW_Current:         ab->current = tagval; break;
  325.         case ARROW_IncreaseRate:    ab->rate_increase = tagval + 100; break;
  326.         case ARROW_MaxRate:         ab->rate_max = tagval * 100; break;
  327.         }
  328.     }
  329.     ab->current = clamp(ab->min,ab->current,ab->max);
  330.     return 0;
  331. }
  332.  
  333. /* ============================================================================ *
  334.  *  dispatch function for the ArrowButton Class
  335.  * ============================================================================ */
  336.  
  337. static long __asm __saveds ourhook (
  338.     register __a0 Class *cl,
  339.     register __a1 struct gpInput *msg,
  340.     register __a2 struct Gadget *g,
  341.     register __a6 struct Library *IntuitionBase)
  342. {   long                refresh = 0;
  343.     struct ArrowButton  *ab;
  344.     static struct ArrowButton init_ab = { 0,100,0,100,10000 };
  345.  
  346.     switch ( msg->MethodID ) {
  347.  
  348.     case GM_RENDER:
  349.         arrowdraw(cl, (struct gpRender *)msg, g);
  350.         break;
  351.  
  352.     case GM_HITTEST:
  353.         return GMR_GADGETHIT;
  354.  
  355.     case GM_GOACTIVE:
  356.     case GM_HANDLEINPUT:
  357.         return arrowhandle(cl,msg,g);
  358.  
  359.     case GM_GOINACTIVE:
  360.         break;
  361.  
  362.     case OM_NEW:
  363.         g = (struct Gadget *)DoSuperMethodA( cl, (Object *)g, (Msg)msg);
  364.         if (g == NULL) return NULL;
  365.  
  366.         ab = INST_DATA( cl, g );
  367.         *ab = init_ab;
  368.         setArrowButtonAttrs( cl, (Object *)g, (struct opSet *)msg );
  369.  
  370.         return (long)g;
  371.  
  372.     case OM_SET:
  373.         DoSuperMethodA( cl, (Object *)g, (Msg)msg );    /* set attibutes        */
  374.         refresh |= setArrowButtonAttrs( cl, (Object *)g, (struct opSet *)msg );
  375.         return 0;
  376.  
  377.     default:
  378.         return (LONG) DoSuperMethodA( cl, (Object *)g, (Msg)msg );
  379.     }
  380.     return 0;
  381. }
  382.  
  383. /* ============================================================================ *
  384.  *  initArrowButtonClass: create data used by all Arrow Buttons
  385.  * ============================================================================ */
  386.  
  387. Class *initArrowButtonClass(void)
  388. {   Class *cl;
  389.  
  390.     if (cl = MakeClass(                         /* Ask Intuition to make it     */
  391.         NULL,                                   /* Class ID (none)              */
  392.         "gadgetclass", NULL,                    /* superclass is public, tho... */
  393.         sizeof (struct ArrowButton),            /* Size of instance data        */
  394.         0 ))                                    /* No flags...                  */
  395.     {
  396.         cl->cl_Dispatcher.h_Entry = (HOOKFUNC)ourhook;
  397.         cl->cl_Dispatcher.h_SubEntry = NULL;
  398.         cl->cl_Dispatcher.h_Data = 0L;
  399.     }
  400.  
  401.     return cl;
  402. }
  403.  
  404. LONG freeArrowButtonClass(Class *cl)
  405. {
  406.     return (LONG)FreeClass(cl);
  407. }
  408.